/*
*  Copyright 2019-2020 Zheng Jie
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package me.liangjun.patient.service.impl;

import me.liangjun.patient.domain.Patient;
import me.liangjun.patient.service.dto.*;
import me.liangjun.patient.util.PatientUtil;
import me.liangjun.util.SqlParamUtil;
import me.zhengjie.config.ProvinceInfo;
import me.zhengjie.utils.*;
import lombok.RequiredArgsConstructor;
import me.liangjun.patient.repository.PatientRepository;
import me.liangjun.patient.service.PatientService;
import me.liangjun.patient.service.mapstruct.PatientMapper;
import org.springframework.data.domain.Example;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.math.BigInteger;
import java.sql.Date;
import java.time.LocalDate;
import java.util.*;
import java.io.IOException;
import javax.persistence.*;
import javax.servlet.http.HttpServletResponse;

/**
* @website https://el-admin.vip
* @description 服务实现
* @author wei
* @date 2021-09-05
**/
@Service
@RequiredArgsConstructor
public class PatientServiceImpl implements PatientService {

    private final PatientRepository patientRepository;
    private final PatientMapper patientMapper;

    private final EntityManager entityManager;

    @Override
    public Map<String,Object> queryAll(PatientQueryCriteria criteria, Pageable pageable){
        Page<Patient> page = patientRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
        return PageUtil.toPage(page.map(patientMapper::toDto));
    }

    @Override
    public List<PatientDto> queryAll(PatientQueryCriteria criteria){
        List<Patient> all = patientRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder));
        return patientMapper.toDto(all);
    }

    @Override
    @Transactional
    public PatientDto findById(Long id) {
        Patient patient = patientRepository.findById(id).orElseGet(Patient::new);
        ValidationUtil.isNull(patient.getId(), "Patient", "id", id);
        PatientDto patientDto = patientMapper.toDto(patient);
        PatientUtil.patient2resources(patientDto);
        return patientDto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PatientDto create(Patient resources) {
        PatientUtil.resources2patient(resources);
        resources.setPercentage(10);
        return patientMapper.toDto(patientRepository.save(resources));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(Patient resources) {
        Patient patient = patientRepository.findById(resources.getId()).orElseGet(Patient::new);
        ValidationUtil.isNull( patient.getId(),"Patient","id",resources.getId());
        PatientUtil.resources2patient(resources);
        patient.copy(resources);
        patientRepository.save(patient);
    }

    @Override
    public void deleteAll(Long[] ids) {
        for (Long id : ids) {
            patientRepository.deleteById(id);
        }
    }

    @Override
    public void download(List<PatientDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (PatientDto patient : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("患者名称", patient.getName());
            map.put("性别", patient.getSex());
            map.put("电话", patient.getPhone());
            map.put("年龄", patient.getAge());
            map.put("体力劳动等级", patient.getLevel());
            map.put("民族", patient.getNation());
            map.put("教育程度", patient.getEducationBackground());
            map.put("是否结婚", patient.getMarry());
            map.put("生育情况", patient.getFertility());
            map.put("职业", patient.getProfession());
            map.put("首诊医院", patient.getFirstHospital());
            map.put("首诊科室", patient.getFirstOffice());
            map.put("是否抽血", patient.getDrawBlood());
            map.put("入组时间", patient.getJoinTime());
            map.put("联系人", patient.getContacts());
            map.put("联系电话", patient.getPhone2());
            map.put("联系电话1", patient.getPhone1());
            map.put("省", patient.getProvince());
            map.put("市", patient.getCity());
            map.put("区", patient.getArea());
            map.put("长期居住地省", patient.getProvince2());
            map.put("长期居住地市", patient.getCity2());
            map.put("长期居住区", patient.getArea2());
            map.put("出生日期", patient.getBirth());
            map.put("家庭收入", patient.getMoney());
            map.put("病例完整度", patient.getPercentage());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public PatientCensusDto census() {
        long patientCount = patientRepository.count();
        Patient patient = new Patient();
        patient.setSex(1);
        Example<Patient> example = Example.of(patient);
        long boyCount = patientRepository.count(example);
        patient.setSex(2);
        example = Example.of(patient);
        long girlCount = patientRepository.count(example);
        Date date = Date.valueOf(LocalDate.now().minusDays(90));
        long newAddCount = patientRepository.count((Specification<Patient>) (root, criteriaQuery, criteriaBuilder)
                -> criteriaBuilder.greaterThanOrEqualTo(root.get("joinTime"), date));
        long completeCount = patientRepository.count((Specification<Patient>) (root, criteriaQuery, criteriaBuilder)
                -> criteriaBuilder.equal(root.get("percentage"), 100));
        long lackCount = patientRepository.count((Specification<Patient>) (root, criteriaQuery, criteriaBuilder)
                -> criteriaBuilder.notEqual(root.get("percentage"), 100));
        Object[] obj3 = patientRepository.statistics3();
        PieData genderData = new PieData();
        genderData.setName("性别分布");
        genderData.setLegend(Arrays.asList("女","男"));
        genderData.setData(Arrays.asList(
                Pair.builder().name("女").value(String.valueOf(girlCount)).build(),
                Pair.builder().name("男").value(String.valueOf(boyCount)).build()));
        List<Pair> list = new ArrayList<>();
        List<String> strings = new ArrayList<>();
        for (int i = 0; i < obj3.length; i++) {
            list.add(Pair.builder().name((String) ((Object[]) obj3[i])[0]).value(SqlParamUtil.getInt(((Object[]) obj3[i])[1]) + "").build());
            strings.add((String) ((Object[]) obj3[i])[0]);
        }
        PieData ageData = new PieData();
        ageData.setName("年龄分布");
        ageData.setLegend(strings);
        ageData.setData(list);
        List<Tuple> tuples = patientRepository.findGroupByJoinTime();
        Map<String,Integer> result = new HashMap<>();
        for (Tuple tuple : tuples){
            Map<String,Object> temp = new HashMap<>();
            for (TupleElement<?> key : tuple.getElements()){
                temp.put(key.getAlias(),tuple.get(key));
            }
            result.put((String) temp.get("month"),((BigInteger) temp.get("num")).intValue());
        }
        String[] xAxisData = new String[12];
        int[] lineChartData = new int[12];
        LocalDate now = LocalDate.now();
        for (int i=0;i<12;i++){
            xAxisData[i] = now.minusMonths(11-i).format(DateUtil.DFY_M);
            lineChartData[i] = result.get(xAxisData[i])==null ? 0 : result.get(xAxisData[i]);
        }
        PatientCensusDto patientCensusDto = PatientCensusDto.builder()
                .patientCount(patientCount)
                .newAddCount(newAddCount)
                .completeCount(completeCount)
                .lackCount(lackCount)
                .xAxisData(xAxisData)
                .lineChartData(lineChartData)
                .ageData(ageData)
                .genderData(genderData)
                .build();
        return patientCensusDto;
    }

    @Override
    public List<Pair> findPatientGroupByProvince() {
        List<Tuple> tuples = patientRepository.findGroupByProvince();
        Map<String,Integer> result = new HashMap<>();
        for (Tuple tuple : tuples){
            Map<String,Object> temp = new HashMap<>();
            for (TupleElement<?> key : tuple.getElements()){
                temp.put(key.getAlias(),tuple.get(key));
            }
            result.put((String) temp.get("province"),((BigInteger) temp.get("num")).intValue());
        }
        System.out.println(result);
        List<Pair> pairs = new ArrayList<>();
        List<ProvinceInfo> provinceInfos = ProvinceInfo.getAllProvince();
        provinceInfos.forEach(provinceInfo -> {
            System.out.println(provinceInfo);
            System.out.println(result.get(provinceInfo.getCode()));
            Integer value = result.get(provinceInfo.getCode());
            pairs.add(Pair.builder().name(provinceInfo.getName()).value(String.valueOf(value==null?0:value)).build());
        });
        return pairs;
    }
}